home *** CD-ROM | disk | FTP | other *** search
/ Aminet 43 / Aminet 43 (2001)(GTI - Schatztruhe)[!][Jun 2001].iso / Aminet / comm / mail / YAM22src.lha / YAM_AB.c < prev    next >
C/C++ Source or Header  |  2000-11-03  |  47KB  |  1,057 lines

  1. /***************************************************************************
  2.  
  3.  YAM - Yet Another Mailer
  4.  Copyright (C) 2000  Marcel Beck <mbeck@yam.ch>
  5.  
  6.  This program is free software; you can redistribute it and/or modify
  7.  it under the terms of the GNU General Public License as published by
  8.  the Free Software Foundation; either version 2 of the License, or
  9.  (at your option) any later version.
  10.  
  11.  This program is distributed in the hope that it will be useful,
  12.  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  GNU General Public License for more details.
  15.  
  16.  You should have received a copy of the GNU General Public License
  17.  along with this program; if not, write to the Free Software
  18.  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  
  20.  YAM Official Support Site :  http://www.yam.ch
  21.  YAM OpenSource project    :  http://sourceforge.net/projects/yamos/
  22.  
  23. ***************************************************************************/
  24.  
  25. #include "YAM.h"
  26.  
  27. /***************************************************************************
  28.  Module: Address book
  29. ***************************************************************************/
  30.  
  31. /// AB_GotoEntry
  32. //  Searches an entry by alias and activates it
  33. APTR AB_GotoEntry(char *alias)
  34. {
  35.    int hits = 0;
  36.    struct MUIS_Listtree_TreeNode *tn = NULL;
  37.    if (AB_SearchEntry(MUIV_Lt_GetEntry_ListNode_Root, alias, ASM_ALIAS|ASM_USER|ASM_GROUP|ASM_LIST, &hits, &tn))
  38.    {
  39.       DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_Listtree_Open, MUIV_Lt_Open_ListNode_Parent, tn, 0);
  40.       set(G->AB->GUI.LV_ADRESSES, MUIA_Listtree_Active, tn);
  41.    }
  42.    return tn;
  43. }
  44. ///
  45. /// AB_ExpandBD
  46. //  Converts date from numeric into textual format
  47. char *AB_ExpandBD(long date)
  48. {
  49.    static char datestr[SIZE_SMALL];
  50.    if (!date) return "";
  51.    sprintf(datestr, "%02d-%s-%ld", date/1000000, months[((date/10000)%100)-1], date%10000);
  52.    return datestr;
  53. }
  54. ///
  55. /// AB_CompressBD
  56. //  Connverts date from textual into numeric format
  57. long AB_CompressBD(char *datestr)
  58. {
  59.    long d, m, y;
  60.    for (m = 12; m > 0; m--) if (!strnicmp(&datestr[3], months[m-1], 3)) break;
  61.    if (!m) return 0;
  62.    if ((d = atoi(datestr)) < 1 || d > 31) return 0;
  63.    if ((y = atoi(&datestr[7])) < 1800 || y > 2100) return 0;
  64.    return (100*d+m)*10000+y;
  65. }
  66. ///
  67. /// AB_FindTodaysBirthdates (rec)
  68. //  Recursively searches the address book for a given birth date
  69. STACKEXT BOOL AB_FindTodaysBirthdates(struct MUIS_Listtree_TreeNode *list, long today)
  70. {
  71.    struct MUIS_Listtree_TreeNode *tn;
  72.    int wrwin, i;
  73.    
  74.    for (i=0; ; i++)
  75.       if (tn = (struct MUIS_Listtree_TreeNode *)DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_Listtree_GetEntry, list, i, MUIV_Lt_GetEntry_Flags_SameLevel))
  76.       {
  77.          struct ABEntry *ab = tn->tn_User;
  78.          if (ab->Type == AET_GROUP)
  79.          {
  80.             if (!AB_FindTodaysBirthdates(tn, today)) return FALSE;
  81.          }
  82.          else if (ab->Type == AET_USER && ab->BirthDay/10000 == today/10000)
  83.          {
  84.             char question[SIZE_LARGE], *name = *ab->RealName ? ab->RealName : ab->Alias;
  85.             sprintf(question, GetStr(MSG_AB_BirthdayReq), name, today%10000-ab->BirthDay%10000);
  86.             if (MUI_Request(G->App, G->MA->GUI.WI, 0, GetStr(MSG_AB_BirthdayReminder), GetStr(MSG_YesNoReq), question))
  87.             {
  88.                if ((wrwin = MA_NewNew(NULL, 0)) >= 0)
  89.                {
  90.                   setstring(G->WR[wrwin]->GUI.ST_TO, ab->Alias);
  91.                   setstring(G->WR[wrwin]->GUI.ST_SUBJECT, GetStr(MSG_AB_HappyBirthday));
  92.                }
  93.             }
  94.          }
  95.       }
  96.       else break;
  97.    return TRUE;
  98. }
  99. ///
  100. /// AB_CheckBirthdates
  101. //  Searches address book for todays birth days
  102. void AB_CheckBirthdates(void)
  103. {
  104.    long today = DateStamp2Long(NULL);
  105.    AB_FindTodaysBirthdates(MUIV_Lt_GetEntry_ListNode_Root, today);
  106. }
  107. ///
  108. /// AB_SearchEntry (rec)
  109. //  Recursively searches the address book by alias, name or address
  110. STACKEXT int AB_SearchEntry(struct MUIS_Listtree_TreeNode *list, char *text, int mode, int *hits, struct MUIS_Listtree_TreeNode **lasthit)
  111. {
  112.    struct MUIS_Listtree_TreeNode *tn;
  113.    int i;
  114.  
  115.    if (*text) for (i=0; ; i++)
  116.       if (tn = (struct MUIS_Listtree_TreeNode *)DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_Listtree_GetEntry, list, i, MUIV_Lt_GetEntry_Flags_SameLevel))
  117.       {
  118.          struct ABEntry *ab = tn->tn_User;
  119.          int type = ab->Type;
  120.          BOOL found = FALSE;
  121.          if ((type == AET_USER && (mode&ASM_USER)) || (type == AET_LIST && (mode&ASM_LIST)) || (type == AET_GROUP && (mode&ASM_GROUP)))
  122.             if (mode&ASM_COMPLETE)
  123.             {
  124.                int tl = strlen(text);
  125.                switch (mode&ASM_TYPEMASK)
  126.                {
  127.                   case ASM_ALIAS   : found = !Strnicmp(ab->Alias, text, tl); break;
  128.                   case ASM_REALNAME: found = !Strnicmp(ab->RealName, text, tl); break;
  129.                   case ASM_ADDRESS : found = !Strnicmp(ab->Address, text, tl); break;
  130.                }
  131.             }
  132.             else
  133.                switch (mode&ASM_TYPEMASK)
  134.                {
  135.                   case ASM_ALIAS   : found = !Stricmp(ab->Alias, text); break;
  136.                   case ASM_REALNAME: found = !Stricmp(ab->RealName, text); break;
  137.                   case ASM_ADDRESS : found = !Stricmp(ab->Address, text); break;
  138.                }
  139.          if (found) { *lasthit = tn; *hits = *hits+1; };
  140.          if (type == AET_GROUP) AB_SearchEntry(tn, text, mode, hits, lasthit);
  141.       }
  142.       else break;
  143.    return *hits;
  144. }
  145. ///
  146. /// AB_CompleteAlias
  147. //  Auto-completes alias or name in recipient field
  148. char *AB_CompleteAlias(char *text)
  149. {
  150.    char *compl = NULL;
  151.    struct MUIS_Listtree_TreeNode *tn;
  152.    int hits = 0;
  153.    AB_SearchEntry(MUIV_Lt_GetEntry_ListNode_Root, text, ASM_ALIAS|ASM_USER|ASM_LIST|ASM_GROUP|ASM_COMPLETE, &hits, &tn);
  154.    if (hits == 1) compl = ((struct ABEntry *)(tn->tn_User))->Alias;
  155.    else if (!hits)
  156.    {
  157.       AB_SearchEntry(MUIV_Lt_GetEntry_ListNode_Root, text, ASM_REALNAME|ASM_USER|ASM_LIST|ASM_GROUP|ASM_COMPLETE, &hits, &tn);
  158.       if (hits == 1) compl = ((struct ABEntry *)(tn->tn_User))->RealName;
  159.    }
  160.    if (compl) return &compl[strlen(text)]; else return NULL;
  161. }
  162. ///
  163. /// AB_InsertAddress
  164. //  Adds a new recipient to a recipient field
  165. void AB_InsertAddress(APTR string, char *alias, char *name, char *address)
  166. {
  167.    char *p;
  168.    get(string, MUIA_UserData, &p);
  169.    if ((BOOL)p)
  170.    {
  171.       get(string, MUIA_String_Contents, &p);
  172.       if (*p) DoMethod(string, MUIM_BetterString_Insert, ", ", MUIV_BetterString_Insert_EndOfString);
  173.    }
  174.    else setstring(string, "");
  175.    if (*alias) DoMethod(string, MUIM_BetterString_Insert, alias, MUIV_BetterString_Insert_EndOfString);
  176.    else
  177.    {
  178.       if (*name)
  179.       {
  180.          if (strchr(name, ',')) DoMethod(string, MUIM_BetterString_Insert, "\"", MUIV_BetterString_Insert_EndOfString);
  181.          DoMethod(string, MUIM_BetterString_Insert, name, MUIV_BetterString_Insert_EndOfString);
  182.          if (strchr(name, ',')) DoMethod(string, MUIM_BetterString_Insert, "\"", MUIV_BetterString_Insert_EndOfString);
  183.       }
  184.       if (*address)
  185.       {
  186.          if (*name) DoMethod(string, MUIM_BetterString_Insert, " <", MUIV_BetterString_Insert_EndOfString);
  187.          DoMethod(string, MUIM_BetterString_Insert, address, MUIV_BetterString_Insert_EndOfString);
  188.          if (*name) DoMethod(string, MUIM_BetterString_Insert, ">", MUIV_BetterString_Insert_EndOfString);
  189.       }
  190.    }
  191. }
  192. ///
  193. /// AB_FromAddrBook
  194. //  Inserts an address book entry into a recipient string
  195. SAVEDS ASM void AB_FromAddrBook(REG(a1) ULONG *arg)
  196. {
  197.    APTR string;
  198.    struct MUIS_Listtree_TreeNode *active;
  199.  
  200.    if (active = (struct MUIS_Listtree_TreeNode *)DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_Listtree_GetEntry, NULL, MUIV_Lt_GetEntry_Position_Active, 0))
  201.    {
  202.       int winnum = G->AB->WrWin;
  203.       struct ABEntry *addr = (struct ABEntry *)(active->tn_User);
  204.       BOOL openwin = winnum < 0;
  205.       if (!openwin) openwin = !G->WR[winnum];
  206.       if (openwin) G->AB->WrWin = winnum = MA_NewNew(NULL, 0);
  207.       if (winnum >= 0)
  208.       {
  209.          switch (*arg)
  210.          {
  211.             case ABM_TO:      string = G->WR[winnum]->GUI.ST_TO; break;
  212.             case ABM_CC:      string = G->WR[winnum]->GUI.ST_CC; break;
  213.             case ABM_BCC:     string = G->WR[winnum]->GUI.ST_BCC; break;
  214.             case ABM_REPLYTO: string = G->WR[winnum]->GUI.ST_REPLYTO; break;
  215.             case ABM_FROM:    string = G->WR[winnum]->GUI.ST_FROM; break;
  216.             default: string = (APTR)*arg;
  217.          }
  218.          AB_InsertAddress(string, addr->Alias, addr->RealName, "");
  219.       }
  220.    }
  221. }
  222. MakeHook(AB_FromAddrBookHook, AB_FromAddrBook);
  223. ///
  224. /// AB_LoadTree
  225. //  Loads the address book from a file
  226. BOOL AB_LoadTree(char *fname, BOOL append, BOOL sorted)
  227. {
  228.    static struct ABEntry addr;
  229.    struct MUIS_Listtree_Node *parent[8];
  230.    char buffer[SIZE_LARGE];
  231.    FILE *fh;
  232.    int len, nested = 0;
  233.  
  234.    G->AB->Modified = append;
  235.    if (!append) DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_Listtree_Remove, MUIV_Lt_Remove_ListNode_Root, MUIV_Lt_Remove_TreeNode_All, 0);
  236.    parent[nested] = MUIV_Lt_Insert_ListNode_Root;
  237.    if (fh = fopen(fname, "r"))
  238.    {
  239.       GetLine(fh, buffer, SIZE_LARGE);
  240.       if (!strncmp(buffer,"YAB",3))
  241.       {
  242.          int version = buffer[3]-'0';
  243.          set(G->AB->GUI.LV_ADRESSES, MUIA_Listtree_Quiet, TRUE);
  244.          while (GetLine(fh, buffer, SIZE_LARGE))
  245.          {
  246.             clear(&addr, sizeof(struct ABEntry));
  247.             if (!strncmp(buffer, "@USER", 5))
  248.             {
  249.                addr.Type = AET_USER;
  250.                stccpy(addr.Alias   , Trim(&buffer[6]),SIZE_NAME);
  251.                stccpy(addr.Address , Trim(GetLine(fh, buffer, SIZE_LARGE)),SIZE_ADDRESS);
  252.                stccpy(addr.RealName, Trim(GetLine(fh, buffer, SIZE_LARGE)),SIZE_REALNAME);
  253.                stccpy(addr.Comment , Trim(GetLine(fh, buffer, SIZE_LARGE)),SIZE_DEFAULT);
  254.                if (version > 2)
  255.                {
  256.                   stccpy(addr.Phone   , Trim(GetLine(fh, buffer, SIZE_LARGE)),SIZE_DEFAULT);;
  257.                   stccpy(addr.Street  , Trim(GetLine(fh, buffer, SIZE_LARGE)),SIZE_DEFAULT);
  258.                   stccpy(addr.City    , Trim(GetLine(fh, buffer, SIZE_LARGE)),SIZE_DEFAULT);
  259.                   stccpy(addr.Country , Trim(GetLine(fh, buffer, SIZE_LARGE)),SIZE_DEFAULT);
  260.                   stccpy(addr.PGPId   , Trim(GetLine(fh, buffer, SIZE_LARGE)),SIZE_DEFAULT);
  261.                   addr.BirthDay = atol(Trim(GetLine(fh, buffer, SIZE_LARGE)));
  262.                   stccpy(addr.Photo   , Trim(GetLine(fh, buffer, SIZE_LARGE)),SIZE_PATHFILE);
  263.                   if (strcmp(GetLine(fh, buffer, SIZE_LARGE), "@ENDUSER")) stccpy(addr.Homepage,Trim(buffer),SIZE_URL);
  264.                }
  265.                do if (!strcmp(buffer, "@ENDUSER")) break;
  266.                while (GetLine(fh, buffer, SIZE_LARGE));
  267.                DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_Listtree_Insert, addr.Alias[0] ? addr.Alias : addr.RealName, &addr, parent[nested], sorted ?  MUIV_Lt_Insert_PrevNode_Sorted : MUIV_Lt_Insert_PrevNode_Tail, 0);
  268.             }
  269.             else if (!strncmp(buffer, "@LIST", 5))
  270.             {
  271.                char *members;
  272.                addr.Type = AET_LIST;
  273.                stccpy(addr.Alias   , Trim(&buffer[6]), SIZE_NAME);
  274.                if (version > 2)
  275.                {
  276.                   stccpy(addr.Address , Trim(GetLine(fh, buffer, SIZE_LARGE)),SIZE_ADDRESS);
  277.                   stccpy(addr.RealName, Trim(GetLine(fh, buffer, SIZE_LARGE)),SIZE_REALNAME);
  278.                }
  279.                stccpy(addr.Comment , Trim(GetLine(fh, buffer, SIZE_LARGE)), SIZE_DEFAULT);
  280.                members = AllocStrBuf(SIZE_DEFAULT);
  281.                while (GetLine(fh, buffer, SIZE_LARGE))
  282.                {
  283.                   if (!strcmp(buffer, "@ENDLIST")) break;
  284.                   if (!*buffer) continue;
  285.                   members = StrBufCat(members, buffer);
  286.                   members = StrBufCat(members, "\n");
  287.                }
  288.                len = strlen(members)+1;
  289.                addr.Members = malloc(len);
  290.                strcpy(addr.Members, members);
  291.                FreeStrBuf(members);
  292.                DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_Listtree_Insert, addr.Alias, &addr, parent[nested], sorted ?  MUIV_Lt_Insert_PrevNode_Sorted : MUIV_Lt_Insert_PrevNode_Tail, 0);
  293.                free(addr.Members);
  294.             }
  295.             else if (!strncmp(buffer, "@GROUP", 6))
  296.             {
  297.                addr.Type = AET_GROUP;
  298.                stccpy(addr.Alias  , Trim(&buffer[7]), SIZE_NAME);
  299.                stccpy(addr.Comment, Trim(GetLine(fh, buffer, SIZE_LARGE)), SIZE_DEFAULT);
  300.                nested++;
  301.                parent[nested] = (struct MUIS_Listtree_Node *)DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_Listtree_Insert, addr.Alias, &addr, parent[nested-1], MUIV_Lt_Insert_PrevNode_Tail, TNF_LIST);
  302.             }
  303.             else if (!strcmp(buffer,"@ENDGROUP"))
  304.             {
  305.                nested--;
  306.             }
  307.          }
  308.          set(G->AB->GUI.LV_ADRESSES, MUIA_Listtree_Quiet, FALSE);
  309.       }
  310.       else
  311.       {
  312.          fseek(fh, 0, SEEK_SET);
  313.          while (GetLine(fh, buffer, SIZE_LARGE))
  314.          {
  315.             char *p, *p2;
  316.             clear(&addr, sizeof(struct ABEntry));
  317.             if (p = strchr(buffer, ' ')) *p = 0;
  318.             stccpy(addr.Address, buffer, SIZE_ADDRESS);
  319.             if (p)
  320.             {
  321.                stccpy(addr.RealName, ++p, SIZE_REALNAME);
  322.                if (p2 = strchr(p, ' ')) *p2 = 0;
  323.             }
  324.             else if (p2 = strchr(p = buffer, '@')) *p2 = 0;
  325.             stccpy(addr.Alias, p, SIZE_NAME);
  326.             DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_Listtree_Insert, addr.Alias, &addr, parent[nested], sorted ?  MUIV_Lt_Insert_PrevNode_Sorted : MUIV_Lt_Insert_PrevNode_Tail, 0);
  327.          }
  328.       }
  329.       fclose(fh);
  330.    }
  331.    else return False;
  332.    return True;
  333. }
  334. ///
  335. /// AB_SaveTreeNode (rec)
  336. //  Recursively saves an address book node
  337. STACKEXT void AB_SaveTreeNode(FILE *fh, struct MUIS_Listtree_TreeNode *list)
  338. {
  339.    struct MUIS_Listtree_TreeNode *tn;
  340.    struct ABEntry *ab;
  341.    int i;
  342.         
  343.    for (i=0; ; i++)
  344.       if (tn = (struct MUIS_Listtree_TreeNode *)DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_Listtree_GetEntry, list, i, MUIV_Lt_GetEntry_Flags_SameLevel))
  345.       {
  346.          ab = tn->tn_User;
  347.          switch (ab->Type)
  348.          {
  349.             case AET_USER:  fprintf(fh, "@USER %s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%08ld\n%s\n%s\n@ENDUSER\n", ab->Alias, ab->Address, ab->RealName, ab->Comment,
  350.                                ab->Phone, ab->Street, ab->City, ab->Country, ab->PGPId, ab->BirthDay, ab->Photo, ab->Homepage);
  351.                             break;
  352.             case AET_LIST:  fprintf(fh, "@LIST %s\n%s\n%s\n%s\n%s\n@ENDLIST\n", ab->Alias, ab->Address, ab->RealName, ab->Comment, ab->Members);
  353.                             break;
  354.             case AET_GROUP: fprintf(fh, "@GROUP %s\n%s\n", ab->Alias, ab->Comment);
  355.                             AB_SaveTreeNode(fh, tn);
  356.                             fputs("@ENDGROUP\n", fh);
  357.                             break;
  358.          }
  359.       }
  360.       else break;
  361. }
  362. ///
  363. /// AB_SaveTree
  364. //  Saves the address book to a file
  365. BOOL AB_SaveTree(char *fname)
  366. {
  367.    FILE *fh;
  368.  
  369.    if (fh = fopen(fname, "w"))
  370.    {
  371.       fputs("YAB3 - YAM Addressbook\n", fh);
  372.       AB_SaveTreeNode(fh, MUIV_Lt_GetEntry_ListNode_Root);
  373.       fclose(fh);
  374.       AppendLogVerbose(70, GetStr(MSG_LOG_SavingABook), fname, "", "", "");
  375.       return TRUE;
  376.    }
  377.    ER_NewError(GetStr(MSG_ER_CantCreateFile), fname, NULL);
  378.    return FALSE;
  379. }
  380. ///
  381. /// AB_DoubleClick
  382. //  User double-clicked in the address book
  383. SAVEDS void AB_DoubleClick(void)
  384. {
  385.    extern void AB_EditFunc(void);
  386.  
  387.    if (G->AB->WrWin >= 0) if (G->WR[G->AB->WrWin])
  388.    {
  389.       struct WR_GUIData *gui = &G->WR[G->AB->WrWin]->GUI;
  390.       APTR obj = NULL;
  391.       switch (G->AB->Mode)
  392.       {
  393.          case ABM_TO:      obj = gui->ST_TO; break;
  394.          case ABM_CC:      obj = gui->ST_CC; break;
  395.          case ABM_BCC:     obj = gui->ST_BCC; break;
  396.          case ABM_FROM:    obj = gui->ST_FROM; break;
  397.          case ABM_REPLYTO: obj = gui->ST_REPLYTO; break;
  398.       }
  399.       DoMethod(G->App, MUIM_CallHook, &AB_FromAddrBookHook, obj);
  400.       set(G->AB->GUI.WI, MUIA_Window_CloseRequest, TRUE);
  401.       return;
  402.    }
  403.    AB_EditFunc();
  404. }
  405. MakeHook(AB_DoubleClickHook, AB_DoubleClick);
  406. ///
  407.  
  408. /// AB_Sort
  409. //  Sorts the address book
  410. SAVEDS ASM void AB_Sort(REG(a1) int *arg)
  411. {
  412.    char fname[SIZE_PATHFILE];
  413.    strmfp(fname, C->TempDir, ".addressbook.tmp");
  414.    if (AB_SaveTree(fname))
  415.    {
  416.       G->AB->SortBy = *arg;
  417.       AB_LoadTree(fname, FALSE, TRUE);
  418.       remove(fname);
  419.       G->AB->Modified = TRUE;
  420.    }
  421. }
  422. MakeHook(AB_SortHook, AB_Sort);
  423. ///
  424. /// AB_NewABookFunc
  425. //  Clears entire address book
  426. SAVEDS void AB_NewABookFunc(void)
  427. {
  428.    DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_Listtree_Remove, MUIV_Lt_Remove_ListNode_Root, MUIV_Lt_Remove_TreeNode_All, 0);
  429.    G->AB->Modified = FALSE;
  430. }
  431. MakeHook(AB_NewABookHook, AB_NewABookFunc);
  432. ///
  433. /// AB_OpenABookFunc
  434. //  Loads selected address book
  435. SAVEDS void AB_OpenABookFunc(void)
  436. {
  437.    if (ReqFile(ASL_ABOOK,G->AB->GUI.WI, GetStr(MSG_Open), 0, G->MA_MailDir, ""))
  438.    {
  439.       strmfp(G->AB_Filename, G->ASLReq[ASL_ABOOK]->fr_Drawer, G->ASLReq[ASL_ABOOK]->fr_File);
  440.       AB_LoadTree(G->AB_Filename, FALSE, FALSE);
  441.    }
  442. }
  443. MakeHook(AB_OpenABookHook, AB_OpenABookFunc);
  444. ///
  445. /// AB_AppendABookFunc
  446. //  Appends selected address book
  447. SAVEDS void AB_AppendABookFunc(void)
  448. {
  449.    if (ReqFile(ASL_ABOOK,G->AB->GUI.WI, GetStr(MSG_Append), 0, G->MA_MailDir, ""))
  450.    {
  451.       char aname[SIZE_PATHFILE];
  452.       strmfp(aname, G->ASLReq[ASL_ABOOK]->fr_Drawer, G->ASLReq[ASL_ABOOK]->fr_File);
  453.       AB_LoadTree(aname, TRUE, FALSE);
  454.    }
  455. }
  456. MakeHook(AB_AppendABookHook, AB_AppendABookFunc);
  457. ///
  458. /// AB_SaveABookFunc
  459. //  Saves address book using the default name
  460. SAVEDS void AB_SaveABookFunc(void)
  461. {
  462.    Busy(GetStr(MSG_BusySavingAB), G->AB_Filename, 0, 0);
  463.    AB_SaveTree(G->AB_Filename);
  464.    G->AB->Modified = FALSE;
  465.    BusyEnd;
  466. }
  467. MakeHook(AB_SaveABookHook, AB_SaveABookFunc);
  468. ///
  469. /// AB_SaveABookAsFunc
  470. //  Saves address book under a different name
  471. SAVEDS void AB_SaveABookAsFunc(void)
  472. {
  473.    if (ReqFile(ASL_ABOOK,G->AB->GUI.WI, GetStr(MSG_SaveAs), 1, G->MA_MailDir, ""))
  474.    {
  475.       strmfp(G->AB_Filename, G->ASLReq[ASL_ABOOK]->fr_Drawer, G->ASLReq[ASL_ABOOK]->fr_File);
  476.       AB_SaveABookFunc();
  477.    }
  478. }
  479. MakeHook(AB_SaveABookAsHook, AB_SaveABookAsFunc);
  480. ///
  481. /// AB_PrintField
  482. //  Formats and prints a single field
  483. void AB_PrintField(FILE *prt, char *fieldname, char *field)
  484. {
  485.    char *format = "%-20.20s: %-50.50s\n";
  486.    if (*field) fprintf(prt, format, StripUnderscore(fieldname), field);
  487. }
  488. ///
  489. /// AB_PrintShortEntry
  490. //  Prints an address book entry in compact format
  491. void AB_PrintShortEntry(FILE *prt, struct ABEntry *ab)
  492. {
  493.    char types[3] = { 'P','L','G' };
  494.    fprintf(prt, "%c %-12.12s %-20.20s %-36.36s\n", types[ab->Type-AET_USER],
  495.       ab->Alias, ab->RealName, ab->Type == AET_USER ? ab->Address : ab->Comment);
  496. }
  497. ///
  498. /// AB_PrintLongEntry
  499. //  Prints an address book entry in detailed format
  500. void AB_PrintLongEntry(FILE *prt, struct ABEntry *ab)
  501. {
  502.    fputs("------------------------------------------------------------------------\n", prt);
  503.    switch (ab->Type)
  504.    {
  505.       case AET_USER:
  506.          AB_PrintField(prt, GetStr(MSG_AB_PersonAlias), ab->Alias);
  507.          AB_PrintField(prt, GetStr(MSG_EA_RealName), ab->RealName);
  508.          AB_PrintField(prt, GetStr(MSG_EA_EmailAddress), ab->Address);
  509.          AB_PrintField(prt, GetStr(MSG_EA_PGPId), ab->PGPId);
  510.          AB_PrintField(prt, GetStr(MSG_EA_Homepage), ab->Homepage);
  511.          AB_PrintField(prt, GetStr(MSG_EA_Street), ab->Street);
  512.          AB_PrintField(prt, GetStr(MSG_EA_City), ab->City);
  513.          AB_PrintField(prt, GetStr(MSG_EA_Country), ab->Country);
  514.          AB_PrintField(prt, GetStr(MSG_EA_Phone), ab->Phone);
  515.          AB_PrintField(prt, GetStr(MSG_EA_DOB), AB_ExpandBD(ab->BirthDay));
  516.          break;
  517.       case AET_LIST:
  518.          AB_PrintField(prt, GetStr(MSG_AB_ListAlias), ab->Alias);
  519.          AB_PrintField(prt, GetStr(MSG_EA_MLName), ab->RealName);
  520.          AB_PrintField(prt, GetStr(MSG_EA_ReturnAddress), ab->Address);
  521.          if (ab->Members)
  522.          {
  523.             BOOL header = FALSE;
  524.             char *ptr;
  525.             for (ptr = ab->Members; *ptr; ptr++)
  526.             {
  527.                char *nptr = strchr(ptr, '\n');
  528.                if (nptr) *nptr = 0; else break;
  529.                if (!header) { AB_PrintField(prt, GetStr(MSG_EA_Members), ptr); header = TRUE; }
  530.                else fprintf(prt, "                      %s\n", ptr);
  531.                *nptr = '\n';
  532.                ptr = nptr;
  533.             }
  534.          }
  535.          break;
  536.       case AET_GROUP:
  537.          AB_PrintField(prt, GetStr(MSG_AB_GroupAlias), ab->Alias);
  538.    }
  539.    AB_PrintField(prt, GetStr(MSG_EA_Description), ab->Comment);
  540. }
  541.  
  542. ///
  543. /// AB_PrintLevel (rec)
  544. //  Recursively prints an address book node
  545. STACKEXT void AB_PrintLevel(struct MUIS_Listtree_TreeNode *list, FILE *prt, int mode)
  546. {
  547.    struct MUIS_Listtree_TreeNode *tn;
  548.    int i;
  549.    
  550.    for (i=0; ; i++)
  551.       if (tn = (struct MUIS_Listtree_TreeNode *)DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_Listtree_GetEntry, list, i, MUIV_Lt_GetEntry_Flags_SameLevel))
  552.       {
  553.          struct ABEntry *ab = tn->tn_User;
  554.          if (mode == 1) AB_PrintLongEntry(prt, ab); else AB_PrintShortEntry(prt, ab);
  555.          if (ab->Type == AET_GROUP) AB_PrintLevel(tn, prt, mode);
  556.       }
  557.       else break;
  558. }
  559. ///
  560. /// AB_PrintABookFunc
  561. //  Prints the entire address book in compact or detailed format
  562. SAVEDS void AB_PrintABookFunc(void)
  563. {
  564.    FILE *prt;
  565.    int mode = MUI_Request(G->App, G->AB->GUI.WI, 0, GetStr(MSG_Print), GetStr(MSG_AB_PrintReqGads), GetStr(MSG_AB_PrintReq));
  566.    if (!mode) return;
  567.    if (C->PrinterCheck) if (!CheckPrinter()) return;
  568.    if (prt = fopen("PRT:", "w"))
  569.    {
  570.       Busy(GetStr(MSG_BusyPrintingAB), "", 0, 0);
  571.       fprintf(prt, "%s\n", G->AB_Filename);
  572.       if (mode == 2)
  573.       {
  574.          fprintf(prt, "\n  %-12.12s %-20.20s %s/%s\n", GetStr(MSG_AB_AliasFld), GetStr(MSG_EA_RealName), GetStr(MSG_EA_EmailAddress), GetStr(MSG_EA_Description));
  575.          fputs("------------------------------------------------------------------------\n", prt);
  576.       }
  577.       AB_PrintLevel(MUIV_Lt_GetEntry_ListNode_Root, prt, mode);
  578.       fclose(prt);
  579.       BusyEnd;
  580.    }
  581. }
  582. MakeHook(AB_PrintABookHook, AB_PrintABookFunc);
  583. ///
  584. /// AB_PrintFunc
  585. //  Prints selected address book entry in detailed format
  586. SAVEDS void AB_PrintFunc(void)
  587. {
  588.    FILE *prt;
  589.    struct MUIS_Listtree_TreeNode *tn;
  590.    if (tn = (struct MUIS_Listtree_TreeNode *)DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_Listtree_GetEntry, MUIV_Lt_GetEntry_ListNode_Active, MUIV_Lt_GetEntry_Position_Active, 0))
  591.    {
  592.       if (C->PrinterCheck) if (!CheckPrinter()) return;
  593.       if (prt = fopen("PRT:", "w"))
  594.       {
  595.          struct ABEntry *ab = (struct ABEntry *)(tn->tn_User);
  596.          set(G->App, MUIA_Application_Sleep, TRUE);
  597.          AB_PrintLongEntry(prt, ab);
  598.          if (ab->Type == AET_GROUP) AB_PrintLevel(tn, prt, 1);
  599.          fclose(prt);
  600.          set(G->App, MUIA_Application_Sleep, FALSE);
  601.       }
  602.    }
  603. }
  604. MakeHook(AB_PrintHook, AB_PrintFunc);
  605. ///
  606. /// AB_AddEntryFunc
  607. //  Add a new entry to the address book
  608. SAVEDS ASM void AB_AddEntryFunc(REG(a1) int *arg)
  609. {
  610.    EA_Init(*arg, NULL);
  611. }
  612. MakeHook(AB_AddEntryHook, AB_AddEntryFunc);
  613. ///
  614. /// AB_EditFunc
  615. //  Modifies selected address book entry
  616. SAVEDS void AB_EditFunc(void)
  617. {
  618.    struct MUIS_Listtree_TreeNode *tn;
  619.    if (tn = (struct MUIS_Listtree_TreeNode *)DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_Listtree_GetEntry, MUIV_Lt_GetEntry_ListNode_Active, MUIV_Lt_GetEntry_Position_Active, 0))
  620.    {
  621.       struct ABEntry *ab = (struct ABEntry *)(tn->tn_User);
  622.       int winnum = EA_Init(ab->Type, tn);
  623.       if (winnum >= 0) EA_Setup(winnum, ab);
  624.    }
  625. }
  626. MakeHook(AB_EditHook, AB_EditFunc);
  627. ///
  628. /// AB_DeleteFunc
  629. //  Deletes selected address book entry
  630. SAVEDS void AB_DeleteFunc(void)
  631. {
  632.    DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_Listtree_Remove, NULL, MUIV_Lt_Remove_TreeNode_Active, 0);
  633.    G->AB->Modified = TRUE;
  634. }
  635. MakeHook(AB_DeleteHook, AB_DeleteFunc);
  636. ///
  637. /// AB_DuplicateFunc
  638. //  Duplicates selected address book entry
  639. SAVEDS void AB_DuplicateFunc(void)
  640. {
  641.    struct MUIS_Listtree_TreeNode *tn;
  642.    if (tn = (struct MUIS_Listtree_TreeNode *)DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_Listtree_GetEntry, MUIV_Lt_GetEntry_ListNode_Active, MUIV_Lt_GetEntry_Position_Active, 0))
  643.    {
  644.       struct ABEntry *ab = (struct ABEntry *)(tn->tn_User);
  645.       int winnum = EA_Init(ab->Type, NULL);
  646.       if (winnum >= 0) 
  647.       {
  648.          char buf[SIZE_NAME];
  649.          int len;
  650.          EA_Setup(winnum, ab);
  651.          strcpy(buf, ab->Alias);
  652.          if (len = strlen(buf))
  653.          {
  654.             if (isdigit(buf[len-1])) buf[len-1]++;
  655.             else if (len < SIZE_NAME-1) strcat(buf, "2");
  656.             else buf[len-1] = '2';
  657.             setstring(G->EA[winnum]->GUI.ST_ALIAS, buf);
  658.          }
  659.       }
  660.    }
  661. }
  662. MakeHook(AB_DuplicateHook, AB_DuplicateFunc);
  663. ///
  664. /// AB_FindEntry (rec)
  665. //  Recursively searches an address book node for a given pattern
  666. STACKEXT BOOL AB_FindEntry(struct MUIS_Listtree_TreeNode *list, char *pattern, int mode, char **result)
  667. {
  668.    APTR lv = G->AB->GUI.LV_ADRESSES;
  669.    struct MUIS_Listtree_TreeNode *tn;
  670.    int i;
  671.    
  672.    for (i=0; ; i++)
  673.       if (tn = (struct MUIS_Listtree_TreeNode *)DoMethod(lv, MUIM_Listtree_GetEntry, list, i, MUIV_Lt_GetEntry_Flags_SameLevel))
  674.       {
  675.          struct ABEntry *ab = tn->tn_User;
  676.          if (ab->Type == AET_GROUP)
  677.          {
  678.             if (!AB_FindEntry(tn, pattern, mode, result)) return FALSE;
  679.          }
  680.          else
  681.          {
  682.             int found = 0, winnum;
  683.             switch (mode)
  684.             {
  685.                case ABF_RX_NAME:       if (ab->Type != AET_GROUP) found |= astcsma(ab->RealName, pattern); break;
  686.                case ABF_RX_EMAIL:      if (ab->Type != AET_GROUP) found |= astcsma(ab->Address, pattern); break;
  687.                case ABF_RX_NAMEEMAIL:  if (ab->Type != AET_GROUP) found |= astcsma(ab->RealName, pattern) | astcsma(ab->Address, pattern); break;
  688.                default:
  689.                   found |= astcsma(ab->Alias, pattern) | astcsma(ab->Comment, pattern);
  690.                   if (ab->Type != AET_GROUP) found |= astcsma(ab->RealName, pattern) | astcsma(ab->Address, pattern);
  691.                   if (ab->Type == AET_USER) found |= astcsma(ab->Homepage, pattern) | astcsma(ab->Street, pattern) | astcsma(ab->City, pattern) | astcsma(ab->Country, pattern) | astcsma(ab->Phone, pattern);
  692.             }
  693.             if (found)
  694.             {
  695.                G->AB->Hits++;
  696.                if (mode == ABF_USER)
  697.                {
  698.                   char buf[SIZE_LARGE];
  699.                   DoMethod(lv, MUIM_Listtree_Open, MUIV_Lt_Open_ListNode_Parent, tn, 0);
  700.                   set(lv, MUIA_Listtree_Active, tn);
  701.                   sprintf(buf, GetStr(MSG_AB_FoundEntry), ab->Alias, ab->RealName);
  702.                   switch (MUI_Request(G->App, G->AB->GUI.WI, 0, GetStr(MSG_AB_FindEntry), GetStr(MSG_AB_FoundEntryGads), buf))
  703.                   {
  704.                      case 1: break;
  705.                      case 2: if ((winnum = EA_Init(ab->Type, tn)) >= 0) EA_Setup(winnum, ab);
  706.                      case 0: return FALSE;
  707.                   }
  708.                }
  709.                else if (result) *result++ = ab->Alias;
  710.             }
  711.          }
  712.       }
  713.       else break;
  714.    return TRUE;
  715. }
  716. ///
  717. /// AB_FindFunc
  718. //  Searches address book
  719. SAVEDS void AB_FindFunc(void)
  720. {
  721.    static char pattern[SIZE_PATTERN] = { 0 };
  722.  
  723.    G->AB->Hits = 0;
  724.    if (StringRequest(pattern, SIZE_PATTERN, GetStr(MSG_AB_FindEntry), GetStr(MSG_AB_FindEntryReq), GetStr(MSG_AB_StartSearch), NULL, GetStr(MSG_Cancel), FALSE, G->AB->GUI.WI))
  725.    {
  726.       AB_FindEntry(MUIV_Lt_GetEntry_ListNode_Root, pattern, ABF_USER, NULL);
  727.       if (!G->AB->Hits) MUI_Request(G->App, G->AB->GUI.WI, 0, GetStr(MSG_AB_FindEntry), GetStr(MSG_OkayReq), GetStr(MSG_AB_NoneFound));
  728.    }
  729. }
  730. MakeHook(AB_FindHook, AB_FindFunc);
  731. ///
  732.  
  733. /// AB_OpenFunc
  734. //  Open address book window
  735. SAVEDS ASM void AB_OpenFunc(REG(a1) int *arg)
  736. {
  737.    struct AB_ClassData *ab = G->AB;
  738.    char *md = "";
  739.  
  740.    switch (ab->Mode = arg[0])
  741.    {
  742.       case ABM_TO:      md = "(To)"; break;
  743.       case ABM_CC:      md = "(CC)"; break;
  744.       case ABM_BCC:     md = "(BCC)"; break;
  745.       case ABM_FROM:    md = "(From)"; break;
  746.       case ABM_REPLYTO: md = "(Reply-To)"; break;
  747.    }
  748.    ab->WrWin = *md ? arg[1] : -1;
  749.    ab->Modified = FALSE;
  750.    sprintf(ab->WTitle, "%s %s", GetStr(MSG_MA_MAddrBook), md);
  751.    set(ab->GUI.WI, MUIA_Window_Title, ab->WTitle);
  752.    set(ab->GUI.LV_ADRESSES, MUIA_Listtree_Active, MUIV_Lt_Active_Off);
  753.    SafeOpenWindow(ab->GUI.WI);
  754. }
  755. MakeHook(AB_OpenHook, AB_OpenFunc);
  756. ///
  757. /// AB_Close
  758. //  Closes address book window
  759. SAVEDS void AB_Close(void)
  760. {
  761.    if (G->AB->Modified) switch (MUI_Request(G->App, G->AB->GUI.WI, 0, NULL, GetStr(MSG_AB_ModifiedGads), GetStr(MSG_AB_Modified)))
  762.    {
  763.       case 0: return;
  764.       case 1: AB_SaveABookFunc(); break;
  765.       case 2: break;
  766.       case 3: AB_LoadTree(G->AB_Filename, FALSE, FALSE);
  767.    }
  768.    set(G->AB->GUI.WI, MUIA_Window_Open, FALSE);
  769. }
  770. MakeHook(AB_CloseHook, AB_Close);
  771. ///
  772.  
  773. /// AB_LV_ConFunc
  774. //  Address book listview construction hook
  775. SAVEDS ASM struct ABEntry *AB_LV_ConFunc(REG(a1) struct ABEntry *addr)
  776. {
  777.    struct ABEntry *entry = malloc(sizeof(struct ABEntry));
  778.    if (entry)
  779.    {
  780.       memcpy(entry, addr, sizeof(struct ABEntry));
  781.       if (addr->Members) strcpy(entry->Members = malloc(strlen(addr->Members)+1), addr->Members);
  782.    }
  783.    return entry;
  784. }
  785. MakeHook(AB_LV_ConFuncHook, AB_LV_ConFunc);
  786. ///
  787. /// AB_LV_DesFunc
  788. //  Address book listview destruction hook
  789. SAVEDS ASM long AB_LV_DesFunc(REG(a1) struct ABEntry *entry)
  790. {
  791.    if (entry->Members) free(entry->Members);
  792.    free(entry);
  793.    return 0;
  794. }
  795. MakeHook(AB_LV_DesFuncHook, AB_LV_DesFunc);
  796. ///
  797. /// AB_LV_DspFunc
  798. //  Address book listview display hook
  799. SAVEDS ASM long AB_LV_DspFunc(REG(a0) struct Hook *hook, REG(a2) char **array, REG(a1) struct MUIS_Listtree_TreeNode *node)
  800. {
  801.    static char dispal[SIZE_DEFAULT], dispco[SIZE_DEFAULT+8];
  802.    struct AL_Data *data = (APTR)hook->h_Data;
  803.  
  804.    if (node)
  805.    {
  806.       struct ABEntry *entry = node->tn_User;
  807.       if (entry)
  808.       {
  809.          switch (entry->Type)
  810.          {
  811.             case AET_USER:  array[0] = entry->Alias;
  812.                             array[2] = entry->Comment;
  813.                             break;
  814.             case AET_LIST:  sprintf(array[0] = dispal, "\033O[%08lx]%s", data->Image, entry->Alias);
  815.                             array[2] = entry->Comment;
  816.                             break;
  817.             case AET_GROUP: sprintf(array[0] = dispal, MUIX_B"%s", entry->Alias);
  818.                             sprintf(array[2] = dispco, MUIX_B"%s", entry->Comment);
  819.          }
  820.          array[1] = entry->RealName;
  821.          array[3] = entry->Address;
  822.          array[4] = entry->Street;
  823.          array[5] = entry->City;
  824.          array[6] = entry->Country;
  825.          array[7] = entry->Phone;
  826.          array[8] = AB_ExpandBD(entry->BirthDay);
  827.          array[9] = entry->PGPId;
  828.          array[10]= entry->Homepage;
  829.       }
  830.    }
  831.    else
  832.    {
  833.       array[0] = GetStr(MSG_AB_TitleAlias);
  834.       array[1] = GetStr(MSG_AB_TitleName);
  835.       array[2] = GetStr(MSG_AB_TitleDescription);
  836.       array[3] = GetStr(MSG_AB_TitleAddress);
  837.       array[4] = GetStr(MSG_AB_TitleStreet);
  838.       array[5] = GetStr(MSG_AB_TitleCity);
  839.       array[6] = GetStr(MSG_AB_TitleCountry);
  840.       array[7] = GetStr(MSG_AB_TitlePhone);
  841.       array[8] = GetStr(MSG_AB_TitleBirthDate);
  842.       array[9] = GetStr(MSG_AB_TitlePGPId);
  843.       array[10]= GetStr(MSG_AB_TitleHomepage);
  844.    }
  845.    return 0;
  846. }
  847. MakeHook(AB_LV_DspFuncHook, AB_LV_DspFunc);
  848. ///
  849. /// AB_LV_CmpFunc
  850. //  Address book listview sort hook
  851. SAVEDS ASM long AB_LV_CmpFunc(REG(a2) struct MUIS_Listtree_TreeNode *entry1, REG(a1) struct MUIS_Listtree_TreeNode *entry2)
  852. {
  853.    char *n1, *n2;
  854.    struct ABEntry *ab1 = (struct ABEntry *)entry1->tn_User,
  855.                   *ab2 = (struct ABEntry *)entry2->tn_User;
  856.    int cmp;
  857.    switch (G->AB->SortBy)
  858.    {
  859.       case 1: if (!(n1 = strrchr(ab1->RealName,' '))) n1 = ab1->RealName;
  860.               if (!(n2 = strrchr(ab2->RealName,' '))) n2 = ab2->RealName;
  861.               if (cmp = Stricmp(n1, n2)) return cmp;
  862.               break;
  863.       case 2: if (cmp = Stricmp(ab1->RealName, ab2->RealName)) return cmp;
  864.               break;
  865.       case 3: if (cmp = Stricmp(ab1->Comment, ab2->Comment)) return cmp;
  866.               break;
  867.       case 4: if (cmp = Stricmp(ab1->Address, ab2->Address)) return cmp;
  868.               break;
  869.    }
  870.    return Stricmp(ab1->Alias, ab2->Alias);
  871. }
  872. MakeHook(AB_LV_CmpFuncHook, AB_LV_CmpFunc);
  873. ///
  874.  
  875. /// AB_MakeABFormat
  876. //  Creates format definition for address book listview
  877. void AB_MakeABFormat(APTR lv)
  878. {
  879.    int i;
  880.    char format[SIZE_LARGE];
  881.    BOOL first = TRUE;
  882.    *format = 0;
  883.    for (i = 0; i < ABCOLNUM; i++) if (C->AddrbookCols & (1<<i))
  884.    {
  885.       if (first) first = FALSE; else strcat(format, " BAR,");
  886.       sprintf(&format[strlen(format)], "COL=%ld W=-1", i);
  887.    }
  888.    set(lv, MUIA_Listtree_Format, format);
  889. }
  890. ///
  891. /// AB_New
  892. //  Creates address book window
  893. enum { AMEN_NEW,AMEN_OPEN,AMEN_APPEND,AMEN_SAVE,AMEN_SAVEAS,AMEN_PRINTA,
  894.        AMEN_FIND,AMEN_NEWUSER,AMEN_NEWLIST,AMEN_NEWGROUP,AMEN_EDIT,
  895.        AMEN_DUPLICATE,AMEN_DELETE,AMEN_PRINTE,AMEN_SORTALIAS,
  896.        AMEN_SORTLNAME,AMEN_SORTFNAME,AMEN_SORTDESC,AMEN_SORTADDR,
  897.        AMEN_FOLD,AMEN_UNFOLD };
  898.  
  899. struct AB_ClassData *AB_New(void)
  900. {
  901.    struct AB_ClassData *data;
  902.    APTR list;
  903.  
  904.    if (data = calloc(1, sizeof(struct AB_ClassData)))
  905.    {
  906.       APTR tb_butt[13] = { MSG_AB_TBSave,MSG_AB_TBFind,MSG_Space,
  907.                            MSG_AB_TBNewUser,MSG_AB_TBNewList,MSG_AB_TBNewGroup,MSG_AB_TBEdit,MSG_AB_TBDelete,MSG_AB_TBPrint,MSG_Space,
  908.                            MSG_AB_TBOpenTree,MSG_AB_TBCloseTree,NULL };
  909.       APTR tb_help[13] = { MSG_HELP_AB_BT_SAVE,MSG_HELP_AB_BT_SEARCH,NULL,
  910.                            MSG_HELP_AB_BT_ADDUSER,MSG_HELP_AB_BT_ADDMLIST,MSG_HELP_AB_BT_ADDGROUP,MSG_HELP_AB_BT_EDIT,MSG_HELP_AB_BT_DELETE,MSG_HELP_AB_BT_PRINT,NULL,
  911.                            MSG_HELP_AB_BT_OPEN,MSG_HELP_AB_BT_CLOSE,NULL };
  912.       int i;
  913.       for (i = 0; i < 13; i++) SetupToolbar(&(data->GUI.TB_TOOLBAR[i]), tb_butt[i]?(tb_butt[i]==MSG_Space?"":GetStr(tb_butt[i])):NULL, tb_help[i]?GetStr(tb_help[i]):NULL, 0);
  914.       data->GUI.WI = WindowObject,
  915.          MUIA_HelpNode,"AB_W",
  916.          MUIA_Window_Menustrip, MenustripObject,
  917.             MUIA_Family_Child, MenuObject, MUIA_Menu_Title, GetStr(MSG_CO_CrdABook),
  918.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_New), MUIA_Menuitem_Shortcut,"N", MUIA_UserData,AMEN_NEW, End,
  919.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_Open), MUIA_Menuitem_Shortcut,"O", MUIA_UserData,AMEN_OPEN, End,
  920.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_Append), MUIA_Menuitem_Shortcut,"I", MUIA_UserData,AMEN_APPEND, End,
  921.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,(char)NM_BARLABEL, End,
  922.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_Save), MUIA_Menuitem_Shortcut,"S", MUIA_UserData,AMEN_SAVE, End,
  923.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_SaveAs), MUIA_Menuitem_Shortcut,"A", MUIA_UserData,AMEN_SAVEAS, End,
  924.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,(char)NM_BARLABEL, End,
  925.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_AB_MIFind), MUIA_Menuitem_Shortcut,"F", MUIA_UserData,AMEN_FIND, End,
  926.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_Print), MUIA_UserData,AMEN_PRINTA, End,
  927.             End,
  928.             MUIA_Family_Child, MenuObject, MUIA_Menu_Title, GetStr(MSG_AB_Entry),
  929.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_AB_AddUser), MUIA_Menuitem_Shortcut,"P", MUIA_UserData,AMEN_NEWUSER, End,
  930.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_AB_AddList), MUIA_Menuitem_Shortcut,"L", MUIA_UserData,AMEN_NEWLIST, End,
  931.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_AB_AddGroup), MUIA_Menuitem_Shortcut,"G", MUIA_UserData,AMEN_NEWGROUP, End,
  932.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,(char)NM_BARLABEL, End,
  933.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_Edit), MUIA_Menuitem_Shortcut,"E", MUIA_UserData,AMEN_EDIT, End,
  934.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_AB_Duplicate), MUIA_Menuitem_Shortcut,"D", MUIA_UserData,AMEN_DUPLICATE, End,
  935.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_AB_MIDelete), MUIA_Menuitem_Shortcut,"Del", MUIA_Menuitem_CommandString,TRUE, MUIA_UserData,AMEN_DELETE, End,
  936.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,(char)NM_BARLABEL, End,
  937.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_AB_MIPrint), MUIA_UserData,AMEN_PRINTE, End,
  938.             End,
  939.             MUIA_Family_Child, MenuObject, MUIA_Menu_Title, GetStr(MSG_AB_Sort),
  940.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_AB_SortByAlias), MUIA_Menuitem_Shortcut,"1", MUIA_UserData,AMEN_SORTALIAS, End,
  941.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_AB_SortByName), MUIA_Menuitem_Shortcut,"2", MUIA_UserData,AMEN_SORTLNAME, End,
  942.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_AB_SortByFirstname), MUIA_Menuitem_Shortcut,"3", MUIA_UserData,AMEN_SORTFNAME, End,
  943.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_AB_SortByDesc), MUIA_Menuitem_Shortcut,"4", MUIA_UserData,AMEN_SORTDESC, End,
  944.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_AB_SortByAddress), MUIA_Menuitem_Shortcut,"5", MUIA_UserData,AMEN_SORTADDR, End,
  945.             End,
  946.             MUIA_Family_Child, MenuObject, MUIA_Menu_Title, GetStr(MSG_AB_View),
  947.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_AB_Unfold), MUIA_Menuitem_Shortcut,"<", MUIA_UserData,AMEN_UNFOLD, End,
  948.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_AB_Fold), MUIA_Menuitem_Shortcut,">", MUIA_UserData,AMEN_FOLD, End,
  949.             End,
  950.          End,
  951.          MUIA_Window_ID,MAKE_ID('B','O','O','K'),
  952.          WindowContents, VGroup,
  953.             Child, C->HideGUIElements & HIDE_TBAR ?
  954.                (HGroup,
  955.                   MUIA_HelpNode, "AB_B",
  956.                   Child, data->GUI.BT_TO  = MakeButton("_To:"),
  957.                   Child, data->GUI.BT_CC  = MakeButton("_CC:"),
  958.                   Child, data->GUI.BT_BCC = MakeButton("_BCC:"),
  959.                End) :
  960.                (HGroup, GroupSpacing(0),
  961.                   MUIA_HelpNode, "AB_B",
  962.                   Child, VGroup,
  963.                      MUIA_Weight, 10,
  964.                      MUIA_Group_VertSpacing, 0,
  965.                      Child, data->GUI.BT_TO  = MakeButton("_To:"),
  966.                      Child, data->GUI.BT_CC  = MakeButton("_CC:"),
  967.                      Child, data->GUI.BT_BCC = MakeButton("_BCC:"),
  968.                      Child, HVSpace,
  969.                   End,
  970.                   Child, MUI_MakeObject(MUIO_VBar, 12),
  971.                   Child, HGroupV,
  972.                      Child, data->GUI.TO_TOOLBAR = ToolbarObject,
  973.                         MUIA_Toolbar_ImageType,      MUIV_Toolbar_ImageType_File,
  974.                         MUIA_Toolbar_ImageNormal,    "PROGDIR:Icons/Address.toolbar",
  975.                         MUIA_Toolbar_ImageGhost,     "PROGDIR:Icons/Address_G.toolbar",
  976.                         MUIA_Toolbar_ImageSelect,    "PROGDIR:Icons/Address_S.toolbar",
  977.                         MUIA_Toolbar_Description,    data->GUI.TB_TOOLBAR,
  978.                         MUIA_Toolbar_ParseUnderscore,TRUE,
  979.                         MUIA_Font,                   MUIV_Font_Tiny,
  980.                         MUIA_ShortHelp, TRUE,
  981.                      End,
  982.                      Child, HSpace(0),
  983.                   End,
  984.                End),
  985.             Child, list = ListviewObject,
  986.                MUIA_Listview_DragType,1,
  987.                MUIA_CycleChain,1,
  988.                MUIA_Listview_List,data->GUI.LV_ADRESSES = NewObject(CL_AddressList->mcc_Class, NULL,
  989.                   InputListFrame,
  990.                   MUIA_Listtree_SortHook     ,&AB_LV_CmpFuncHook,
  991.                   MUIA_Listtree_DragDropSort ,TRUE,
  992.                   MUIA_Listtree_Title        ,TRUE,
  993.                   MUIA_Listtree_ConstructHook,&AB_LV_ConFuncHook,
  994.                   MUIA_Listtree_DestructHook ,&AB_LV_DesFuncHook,
  995.                   MUIA_Listtree_EmptyNodes   ,TRUE,
  996.                   MUIA_Font, C->FixedFontList ? MUIV_Font_Fixed : MUIV_Font_List,
  997.                End,
  998.             End,
  999.          End,
  1000.       End;
  1001.       if (data->GUI.WI)
  1002.       {
  1003.          AB_MakeABFormat(data->GUI.LV_ADRESSES);
  1004.          DoMethod(G->App, OM_ADDMEMBER, data->GUI.WI);
  1005.          set(data->GUI.WI, MUIA_Window_DefaultObject, list);
  1006.          SetHelp(data->GUI.BT_TO ,MSG_HELP_AB_BT_TO );
  1007.          SetHelp(data->GUI.BT_CC ,MSG_HELP_AB_BT_CC );
  1008.          SetHelp(data->GUI.BT_BCC,MSG_HELP_AB_BT_BCC);
  1009.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_NEW      ,MUIV_Notify_Application,3,MUIM_CallHook,&AB_NewABookHook,0);
  1010.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_OPEN     ,MUIV_Notify_Application,3,MUIM_CallHook,&AB_OpenABookHook,0);
  1011.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_APPEND   ,MUIV_Notify_Application,3,MUIM_CallHook,&AB_AppendABookHook,0);
  1012.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_SAVE     ,MUIV_Notify_Application,3,MUIM_CallHook,&AB_SaveABookHook,0);
  1013.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_SAVEAS   ,MUIV_Notify_Application,3,MUIM_CallHook,&AB_SaveABookAsHook,0);
  1014.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_PRINTA   ,MUIV_Notify_Application,3,MUIM_CallHook,&AB_PrintABookHook,0);
  1015.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_NEWUSER  ,MUIV_Notify_Application,3,MUIM_CallHook,&AB_AddEntryHook,AET_USER);
  1016.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_NEWLIST  ,MUIV_Notify_Application,3,MUIM_CallHook,&AB_AddEntryHook,AET_LIST);
  1017.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_NEWGROUP ,MUIV_Notify_Application,3,MUIM_CallHook,&AB_AddEntryHook,AET_GROUP);
  1018.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_EDIT     ,MUIV_Notify_Application,3,MUIM_CallHook,&AB_EditHook,0);
  1019.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_DUPLICATE,MUIV_Notify_Application,3,MUIM_CallHook,&AB_DuplicateHook,0);
  1020.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_DELETE   ,MUIV_Notify_Application,3,MUIM_CallHook,&AB_DeleteHook,0);
  1021.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_PRINTE   ,MUIV_Notify_Application,3,MUIM_CallHook,&AB_PrintHook,0);
  1022.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_FIND     ,MUIV_Notify_Application,3,MUIM_CallHook,&AB_FindHook,0);
  1023.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_SORTALIAS,MUIV_Notify_Application,3,MUIM_CallHook,&AB_SortHook,0);
  1024.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_SORTLNAME,MUIV_Notify_Application,3,MUIM_CallHook,&AB_SortHook,1);
  1025.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_SORTFNAME,MUIV_Notify_Application,3,MUIM_CallHook,&AB_SortHook,2);
  1026.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_SORTDESC ,MUIV_Notify_Application,3,MUIM_CallHook,&AB_SortHook,3);
  1027.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_SORTADDR ,MUIV_Notify_Application,3,MUIM_CallHook,&AB_SortHook,4);
  1028.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_FOLD     ,data->GUI.LV_ADRESSES,4,MUIM_Listtree_Close ,NULL,MUIV_Lt_Close_TreeNode_All,0);
  1029.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,AMEN_UNFOLD   ,data->GUI.LV_ADRESSES,4,MUIM_Listtree_Open  ,NULL,MUIV_Lt_Open_TreeNode_All,0);
  1030.          DoMethod(data->GUI.LV_ADRESSES,MUIM_Notify,MUIA_Listtree_DoubleClick,MUIV_EveryTime,MUIV_Notify_Application,3,MUIM_CallHook,&AB_DoubleClickHook,0);
  1031.          DoMethod(data->GUI.BT_TO      ,MUIM_Notify,MUIA_Pressed    ,FALSE,MUIV_Notify_Application           ,3,MUIM_CallHook       ,&AB_FromAddrBookHook,ABM_TO);
  1032.          DoMethod(data->GUI.BT_CC      ,MUIM_Notify,MUIA_Pressed    ,FALSE,MUIV_Notify_Application           ,3,MUIM_CallHook       ,&AB_FromAddrBookHook,ABM_CC);
  1033.          DoMethod(data->GUI.BT_BCC     ,MUIM_Notify,MUIA_Pressed    ,FALSE,MUIV_Notify_Application           ,3,MUIM_CallHook       ,&AB_FromAddrBookHook,ABM_BCC);
  1034.          if (data->GUI.TO_TOOLBAR)
  1035.          {
  1036.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 0, MUIV_Toolbar_Notify_Pressed,FALSE,G->App,3,MUIM_CallHook,&AB_SaveABookHook,0);
  1037.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 1, MUIV_Toolbar_Notify_Pressed,FALSE,G->App,3,MUIM_CallHook,&AB_FindHook,0);
  1038.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 3, MUIV_Toolbar_Notify_Pressed,FALSE,G->App,3,MUIM_CallHook,&AB_AddEntryHook,AET_USER);
  1039.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 4, MUIV_Toolbar_Notify_Pressed,FALSE,G->App,3,MUIM_CallHook,&AB_AddEntryHook,AET_LIST);
  1040.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 5, MUIV_Toolbar_Notify_Pressed,FALSE,G->App,3,MUIM_CallHook,&AB_AddEntryHook,AET_GROUP);
  1041.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 6, MUIV_Toolbar_Notify_Pressed,FALSE,G->App,3,MUIM_CallHook,&AB_EditHook,0);
  1042.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 7, MUIV_Toolbar_Notify_Pressed,FALSE,G->App,3,MUIM_CallHook,&AB_DeleteHook,0);
  1043.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 8, MUIV_Toolbar_Notify_Pressed,FALSE,G->App,3,MUIM_CallHook,&AB_PrintHook,0);
  1044.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify,10, MUIV_Toolbar_Notify_Pressed,FALSE,data->GUI.LV_ADRESSES,4,MUIM_Listtree_Open  ,NULL,MUIV_Lt_Open_TreeNode_All,0);
  1045.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify,11, MUIV_Toolbar_Notify_Pressed,FALSE,data->GUI.LV_ADRESSES,4,MUIM_Listtree_Close ,NULL,MUIV_Lt_Close_TreeNode_All,0);
  1046.          }
  1047.          DoMethod(data->GUI.WI,MUIM_Notify,MUIA_Window_InputEvent   ,"-repeat del" ,MUIV_Notify_Application  ,2,MUIM_CallHook       ,&AB_DeleteHook);
  1048.          DoMethod(data->GUI.WI,MUIM_Notify,MUIA_Window_CloseRequest ,TRUE ,MUIV_Notify_Application           ,2,MUIM_CallHook       ,&AB_CloseHook);
  1049.          return data;
  1050.       }
  1051.       free(data);
  1052.    }
  1053.    return NULL;
  1054. }
  1055. ///
  1056.  
  1057.